home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UUPC11QS.ARJ / MODEM.C < prev    next >
C/C++ Source or Header  |  1991-12-07  |  28KB  |  718 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    m o d e m . c                                                   */
  3. /*                                                                    */
  4. /*    High level modem control routines for UUPC/extended             */
  5. /*                                                                    */
  6. /*    Copyright (c) 1991 by Andrew H. Derbyshire                      */
  7. /*                                                                    */
  8. /*    Change history:                                                 */
  9. /*       21 Apr 91      Create from dcpsys.c                          */
  10. /*--------------------------------------------------------------------*/
  11.  
  12. #include <limits.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <time.h>
  17. #include <sys/types.h>
  18.  
  19. #include "lib.h"
  20. #include "arpadate.h"
  21. #include "checktim.h"
  22. #include "dcp.h"
  23. #include "dcpsys.h"
  24. #include "hlib.h"
  25. #include "hostable.h"
  26. #include "modem.h"
  27. #include "script.h"
  28. #include "security.h"
  29. #include "ssleep.h"
  30. #include "ulib.h"
  31.  
  32. #define MAX_MODEM 8           /* Max length of a modem name          */
  33.  
  34. char *device = NULL;    /*Public to show in login banner     */
  35.  
  36. static char **answer, **initialize, **dropline, **ring, **connect;
  37. static char *dialPrefix, *dialSuffix;
  38.  
  39. static INTEGER chardelay, dialTimeout, modemTimeout, scriptTimeout;
  40. static INTEGER answerTimeout, inspeed;
  41. static INTEGER gWindow, gPacket;
  42.  
  43. typedef enum {
  44.    MODEM_FIXEDSPEED,
  45.    MODEM_DIRECT,
  46.    MODEM_LAST
  47.    } MODEM_FLAGS;
  48.  
  49. static FLAGTABLE modemFlags[] = {
  50.    "direct",      MODEM_DIRECT,      B_UUIO,
  51.    "fixedspeed",  MODEM_FIXEDSPEED,  B_UUIO,
  52.    nil(char)
  53. }           ;
  54.  
  55. static boolean bmodemflag[MODEM_LAST];
  56.  
  57. static CONFIGTABLE modemtable[] = {
  58.    "answer",        (char **) &answer,       B_LIST   | B_UUIO,
  59.    "answertimeout", (char **) &answerTimeout,B_INTEGER| B_UUIO,
  60.    "chardelay",     (char **) &chardelay,    B_INTEGER| B_UUIO,
  61.    "connect",       (char **) &connect,      B_LIST   | B_UUIO,
  62.    "device",        &device,                 B_TOKEN  | B_UUIO | B_REQUIRED,
  63.    "dialprefix",    &dialPrefix,             B_STRING | B_UUIO | B_REQUIRED,
  64.    "dialsuffix",    &dialSuffix,             B_STRING | B_UUIO,
  65.    "dialtimeout",   (char **) &dialTimeout,  B_INTEGER| B_UUIO,
  66.    "gwindowsize",   (char **) &gWindow,      B_INTEGER| B_UUIO,
  67.    "gpacketsize",   (char **) &gPacket,      B_INTEGER| B_UUIO,
  68.    "initialize",    (char **) &initialize,   B_LIST   | B_UUIO,
  69.    "hangup",        (char **) &dropline,     B_LIST   | B_UUIO,
  70.    "modemtimeout",  (char **) &modemTimeout, B_INTEGER| B_UUIO,
  71.    "options",       (char **) bmodemflag,    B_ALL    | B_BOOLEAN,
  72.    "ring",          (char **) &ring,         B_LIST   | B_UUIO,
  73.    "scripttimeout", (char **) &scriptTimeout,B_INTEGER| B_UUIO,
  74.    "inspeed",     (char **) &inspeed,        B_INTEGER| B_UUIO,
  75.    nil(char)
  76. }; /* modemtable */
  77.  
  78. /*--------------------------------------------------------------------*/
  79. /*                    Internal function prototypes                    */
  80. /*--------------------------------------------------------------------*/
  81.  
  82. static boolean getmodem( const char *brand);
  83.  
  84. static boolean dial(char *number, const size_t speed);
  85.  
  86. static boolean sendlist( char **list, int timeout, int lasttimeout);
  87.  
  88. static boolean sendalt( char *string, int timeout);
  89.  
  90. static void autobaud( const size_t speed);
  91.  
  92. /*--------------------------------------------------------------------*/
  93. /*              Define current file name for references               */
  94. /*--------------------------------------------------------------------*/
  95.  
  96. currentfile();
  97.  
  98. /*--------------------------------------------------------------------*/
  99. /*    c a l l u p                                                     */
  100. /*                                                                    */
  101. /*    script processor - nothing fancy!                               */
  102. /*--------------------------------------------------------------------*/
  103.  
  104. CONN_STATE callup()
  105. {
  106.    char *exp;
  107.    int i;
  108.    size_t speed;
  109.  
  110. /*--------------------------------------------------------------------*/
  111. /*      Determine if the window for calling this system is open       */
  112. /*--------------------------------------------------------------------*/
  113.  
  114.    if ( !callnow && equal(flds[FLD_CCTIME],"Never" ))
  115.                                              /* Don't update if we   */
  116.       return CONN_INITIALIZE;                /* never try calling    */
  117.  
  118.    time(&hostp->hstats->ltime); /* Save time of last attempt to call   */
  119.  
  120. /*--------------------------------------------------------------------*/
  121. /*    Check the time of day and whether or not we should call now.    */
  122. /*                                                                    */
  123. /*    If calling a system to set the clock and we determine the       */
  124. /*    system clock is bad (we fail the sanity check of the last       */
  125. /*    connected a host to being in the future), then we ignore the    */
  126. /*    time check field.                                               */
  127. /*--------------------------------------------------------------------*/
  128.  
  129.    if (!(callnow || checktime(flds[FLD_CCTIME],(time_t) 0)))
  130.    {
  131.  
  132.       if ((*flds[FLD_PROTO] != '*') ||       /* Not setting clock?   */
  133.           ((hostp->hstats->ltime >  hostp->hstats->lconnect) &&
  134.            (hostp->hstats->ltime >  630720000L )))
  135.                                              /* Clock okay?          */
  136.       {                                      /* Yes--> Return        */
  137.          hostp->hstatus = wrong_time;
  138.          return CONN_INITIALIZE;
  139.       }
  140.    } /* if */
  141.  
  142. /*--------------------------------------------------------------------*/
  143. /*             Announce we are trying to call the system              */
  144. /*--------------------------------------------------------------------*/
  145.  
  146.    printmsg(1, "callup: calling \"%s\" via %s at %s on %s",
  147.           rmtname, flds[FLD_TYPE], flds[FLD_SPEED], arpadate());
  148.  
  149.    hostp->hstatus = dial_failed; /* Assume failure in the dial */
  150.  
  151.    speed = (size_t) atoi( flds[FLD_SPEED] );
  152.    if (speed < 300)
  153.    {
  154.       printmsg(0,"callup: Modem speed \"%s\" is invalid.",
  155.                   flds[FLD_SPEED]);
  156.       return CONN_INITIALIZE;
  157.    }
  158.  
  159. /*--------------------------------------------------------------------*/
  160. /*                     Get the modem information                      */
  161. /*--------------------------------------------------------------------*/
  162.  
  163.    if (!getmodem(flds[FLD_TYPE]))
  164.       return CONN_INITIALIZE;
  165.  
  166. /*--------------------------------------------------------------------*/
  167. /*                         Dial the telephone                         */
  168. /*--------------------------------------------------------------------*/
  169.  
  170.    if (! dial(flds[FLD_PHONE],speed))
  171.       return CONN_DROPLINE;
  172.  
  173. /*--------------------------------------------------------------------*/
  174. /*             The modem is connected; now login the host             */
  175. /*--------------------------------------------------------------------*/
  176.  
  177.    hostp->hstatus =  script_failed; /* Assume failure          */
  178.    for (i = FLD_EXPECT; i < kflds; i += 2) {
  179.  
  180.       exp = flds[i];
  181.       printmsg(2, "expecting %d of %d \"%s\"", i, kflds, exp);
  182.       if (!sendalt( exp, scriptTimeout ))
  183.       {
  184.          printmsg(0, "SCRIPT FAILED");
  185.          return CONN_DROPLINE;
  186.       } /* if */
  187.  
  188.       printmsg(2, "callup: sending %d of %d \"%s\"",
  189.                    i + 1, kflds, flds[i + 1]);
  190.       sendstr(flds[i + 1]);
  191.  
  192.    } /*for*/
  193.  
  194.    return CONN_PROTOCOL;
  195.  
  196. } /*callup*/
  197.  
  198. /*--------------------------------------------------------------------*/
  199. /*    c a l l h o t                                                   */
  200. /*                                                                    */
  201. /*    Initialize processing when phone is already off the hook        */
  202. /*--------------------------------------------------------------------*/
  203.  
  204. CONN_STATE callhot( const BPS xspeed )
  205. {
  206.    BPS speed;
  207.  
  208.    if ( xspeed == 0)
  209.       speed = inspeed;
  210.    else
  211.       speed = xspeed;
  212.  
  213. /*--------------------------------------------------------------------*/
  214. /*                        Open the serial port                        */
  215. /*--------------------------------------------------------------------*/
  216.  
  217.    if (E_inmodem == NULL)
  218.    {
  219.       printmsg(0,"callin: No modem name supplied for incoming calls!");
  220.       panic();
  221.    } /* if */
  222.  
  223.    if (!getmodem(E_inmodem))  /* Initialize modem configuration      */
  224.       panic();                /* Avoid loop if bad modem name        */
  225.  
  226. /*--------------------------------------------------------------------*/
  227. /*                    Open the communications port                    */
  228. /*--------------------------------------------------------------------*/
  229.  
  230.    if (openline(device, speed, bmodemflag[MODEM_DIRECT] ))
  231.       panic();
  232.  
  233. /*--------------------------------------------------------------------*/
  234. /*                          Initialize stats                          */
  235. /*--------------------------------------------------------------------*/
  236.  
  237.    memset( &remote_stats, 0, sizeof remote_stats);
  238.                               /* Clear remote stats for login        */
  239.    time(&remote_stats.ltime); /* Remember time of last attempt conn  */
  240.    remote_stats.calls ++ ;
  241.    return CONN_HOTLOGIN;
  242.  
  243. } /* callhot */
  244.  
  245. /*--------------------------------------------------------------------*/
  246. /*    c a l l i n                                                     */
  247. /*                                                                    */
  248. /*    Answer the modem in passive mode                                */
  249. /*--------------------------------------------------------------------*/
  250.  
  251. CONN_STATE callin( const char *logintime )
  252. {
  253.    char c;                    /* A character for input buffer        */
  254.  
  255.    int    offset;             /* Time to wait for telephone          */
  256.  
  257. /*--------------------------------------------------------------------*/
  258. /*    Determine how long we can wait for the telephone, up to         */
  259. /*    MAX_INT seconds.  Aside from Turbo C limits, this insures we    */
  260. /*    kick the modem once in a while.                                 */
  261. /*--------------------------------------------------------------------*/
  262.  
  263.    if  (logintime == NULL)    /* Any time specified?                 */
  264.       offset = INT_MAX;       /* No --> Run almost forever           */
  265.    else {                     /* Yes --> Determine elapsed time      */
  266.       int delta = 4096;       /* Rate at which we change offset      */
  267.       boolean split = FALSE;
  268.  
  269.       if (!checktime(logintime,(time_t) 0)) /* Still want system up? */
  270.          return CONN_EXIT;             /* No --> shutdown            */
  271.  
  272.       offset = 0;             /* Wait until end of this minute       */
  273.       while ( ((INT_MAX - delta) > offset ) && (delta > 0))
  274.       {
  275.          printmsg(4,"Current time is %s, offset is %d, offset is %d",
  276.                      arpadate(), offset, delta);
  277.          if (checktime(logintime,(time_t) offset + delta))
  278.             offset += delta;
  279.          else
  280.             split = TRUE;     /* Once we starting splitting, we
  281.                                  never stop                          */
  282.          if ( split )
  283.             delta /= 2;
  284.       } /* while */
  285.    } /* else */
  286.  
  287. /*--------------------------------------------------------------------*/
  288. /*                        Open the serial port                        */
  289. /*--------------------------------------------------------------------*/
  290.  
  291.    if (E_inmodem == NULL)
  292.    {
  293.       printmsg(0,"callin: No modem name supplied for incoming calls!");
  294.       panic();
  295.    } /* if */
  296.  
  297.    if (!getmodem(E_inmodem))  /* Initialize modem configuration      */
  298.       panic();                /* Avoid loop if bad modem name        */
  299.  
  300.    if ((ring == NULL) || (inspeed == 0))
  301.    {
  302.       printmsg(0,"callin: Missing inspeed and/or ring values in modem \
  303. configuration file.");
  304.       panic();
  305.    } /* if */
  306.  
  307. /*--------------------------------------------------------------------*/
  308. /*                    Open the communications port                    */
  309. /*--------------------------------------------------------------------*/
  310.  
  311.    if (openline(device, inspeed, bmodemflag[MODEM_DIRECT]))
  312.       panic();
  313.  
  314. /*--------------------------------------------------------------------*/
  315. /*              Flush the input buffer of any characters              */
  316. /*--------------------------------------------------------------------*/
  317.  
  318.    while (sread(&c ,1,0));    /* Discard trailing trash from modem
  319.                                  connect message                     */
  320.  
  321. /*--------------------------------------------------------------------*/
  322. /*                        Initialize the modem                        */
  323. /*--------------------------------------------------------------------*/
  324.  
  325.    if (!sendlist( initialize, modemTimeout, modemTimeout))
  326.    {
  327.       printmsg(0,"callin: Modem failed to initialize");
  328.       panic();
  329.    }
  330.  
  331. /*--------------------------------------------------------------------*/
  332. /*                   Wait for the telephone to ring                   */
  333. /*--------------------------------------------------------------------*/
  334.  
  335.    if (!sendlist( ring,modemTimeout, offset))
  336.                               /* Did it ring?                        */
  337.    {
  338.       shutdown();
  339.       return CONN_INITIALIZE;     /* No --> Return to caller       */
  340.    }
  341.  
  342.    if(!sendlist(answer, modemTimeout,answerTimeout))
  343.                               /* Pick up the telephone               */
  344.    {
  345.       printmsg(1,"callin: Modem failed to connect to incoming call");
  346.       shutdown();
  347.       return CONN_INITIALIZE;
  348.    }
  349.  
  350. /*--------------------------------------------------------------------*/
  351. /*           The modem is connected; now try to autobaud it           */
  352. /*--------------------------------------------------------------------*/
  353.  
  354.    printmsg(14, "callin: got CONNECT");
  355.    autobaud(inspeed);         /* autobaud the modem                  */
  356.  
  357. /*--------------------------------------------------------------------*/
  358. /*        Flush the input buffer of any other input characters        */
  359. /*--------------------------------------------------------------------*/
  360.  
  361.    while (sread(&c ,1,0));    /* Discard trailing trash from modem
  362.                                  connect message                     */
  363.  
  364.    memset( &remote_stats, 0, sizeof remote_stats);
  365.                               /* Clear remote stats for login        */
  366.    time(&remote_stats.ltime); /* Remember time of last attempt conn  */
  367.    remote_stats.calls ++ ;
  368.    return CONN_LOGIN;
  369.  
  370. } /* callin */
  371.  
  372.  
  373. /*--------------------------------------------------------------------*/
  374. /*    g e t m o d e m                                                 */
  375. /*                                                                    */
  376. /*    Read a modem configuration file                                 */
  377. /*--------------------------------------------------------------------*/
  378.  
  379. static boolean getmodem( const char *brand)
  380. {
  381.    char filename[FILENAME_MAX];
  382.    static char modem[MAX_MODEM+1] = "";
  383.    FILE *fp;
  384.    CONFIGTABLE *tptr;
  385.    size_t subscript;
  386.    boolean success;
  387.  
  388. /*--------------------------------------------------------------------*/
  389. /*                      Validate the modem name                       */
  390. /*--------------------------------------------------------------------*/
  391.  
  392.    if (strlen(brand) > MAX_MODEM)
  393.    {
  394.       printmsg(0,"getmodem: Invalid modem %s; must be %d characters or less",
  395.          brand, modem);
  396.       return FALSE;
  397.    }
  398.  
  399.    if (equal(modem, brand))   /* Already initialized?                */
  400.       return TRUE;            /* Yes --> Don't process it again      */
  401.  
  402. /*--------------------------------------------------------------------*/
  403. /*                        Initialize the table                        */
  404. /*--------------------------------------------------------------------*/
  405.  
  406.    for (tptr = modemtable; tptr->sym != nil(char); tptr++)
  407.       if (tptr->bits & (B_TOKEN | B_STRING | B_LIST | B_CLIST))
  408.          *(tptr->loc) = nil(char);
  409.  
  410.    for (subscript = 0; subscript < MODEM_LAST; subscript++)
  411.       bmodemflag[subscript] = FALSE;
  412.  
  413.    chardelay = 00;            /* Default is no delay between chars    */
  414.    dialTimeout = 40;          /* Default is 40 seconds to dial phone  */
  415.    scriptTimeout = 30;        /* Default is 30 seconds for script data*/
  416.    modemTimeout  = 3;         /* Default is 3 seconds for modem cmds  */
  417.    gWindow = 0;               /* Handle default in dcpgpkt            */
  418.    gPacket = 0;               /* Handle default in dcpgpkt            */
  419.  
  420. /*--------------------------------------------------------------------*/
  421. /*                 Open the modem configuration file                  */
  422. /*--------------------------------------------------------------------*/
  423.  
  424.    if (equaln(brand,"COM",3))
  425.    {
  426.       printmsg(0,"Modem type \"%s\" is invalid; Snuffles suspects \
  427. your %s file is obsolete.", brand, SYSTEMS);
  428.       panic();
  429.    }
  430.  
  431.    sprintf(filename,"%s/%s.MDM",confdir, brand);
  432.    if ((fp = FOPEN(filename, "r", TEXT)) == nil(FILE))
  433.    {
  434.       printmsg(0,"getmodem: Unable to locate configuration for %s",
  435.                brand);
  436.       printerr( filename );
  437.       return FALSE;
  438.    }
  439.  
  440. /*--------------------------------------------------------------------*/
  441. /*                We got the file open, now process it                */
  442. /*--------------------------------------------------------------------*/
  443.  
  444.    printmsg(3,"getmodem: loading modem configuration file %s", filename);
  445.    success = getconfig(fp, MODEM_CONFIG, B_UUIO, modemtable, modemFlags);
  446.    fclose(fp);
  447.    if (!success)
  448.       return FALSE;
  449.  
  450. /*--------------------------------------------------------------------*/
  451. /*         Verify all required modem parameters were supplied         */
  452. /*--------------------------------------------------------------------*/
  453.  
  454.    success = TRUE;
  455.    for (tptr = modemtable; tptr->sym != nil(char); tptr++) {
  456.       if ((tptr->bits & (B_REQUIRED | B_FOUND)) == B_REQUIRED)
  457.       {
  458.          printmsg(0, "getmodem: configuration parameter \"%s\" must be set.",
  459.             tptr->sym);
  460.          success = FALSE;
  461.       } /* if */
  462.    } /* for */
  463.  
  464.    if ( success )             /* Good modem setup?                   */
  465.       strcpy( modem, brand);  /* Yes --> Remember it for next time   */
  466.    return success;
  467.  
  468. } /* getmodem */
  469.  
  470. /*--------------------------------------------------------------------*/
  471. /*    d i a l                                                         */
  472. /*                                                                    */
  473. /*    Generic modem dialer; only major limitation is that autoabaud   */
  474. /*    strings are not configurable                                    */
  475. /*--------------------------------------------------------------------*/
  476.  
  477. static boolean dial(char *number, const size_t speed)
  478. {
  479.    char buf[81];
  480.  
  481. /*--------------------------------------------------------------------*/
  482. /*                        Open the serial port                        */
  483. /*--------------------------------------------------------------------*/
  484.  
  485.    if (openline(device, speed, bmodemflag[MODEM_DIRECT]))
  486.       return FALSE;
  487.  
  488. /*--------------------------------------------------------------------*/
  489. /*              Flush the input buffer of any characters              */
  490. /*--------------------------------------------------------------------*/
  491.  
  492.    while (sread(buf,1,0));    /* Discard trailing trash from modem
  493.                                  connect message                     */
  494.  
  495. /*--------------------------------------------------------------------*/
  496. /*                        Initialize the modem                        */
  497. /*--------------------------------------------------------------------*/
  498.  
  499.    if (!sendlist( initialize, modemTimeout, modemTimeout))
  500.    {
  501.       printmsg(0,"dial: Modem failed to initialize");
  502.       return FALSE;
  503.    }
  504.  
  505. /*--------------------------------------------------------------------*/
  506. /*           Setup the dial string and then dial the modem            */
  507. /*--------------------------------------------------------------------*/
  508.  
  509.    strcpy(buf, dialPrefix);
  510.    strcat(buf, number);
  511.    if (dialSuffix != NULL)
  512.       strcat(buf, dialSuffix);
  513.  
  514.    sendstr( buf );         /* Send the command to the telephone      */
  515.  
  516.    if (!sendlist(connect,  modemTimeout, dialTimeout))
  517.       return FALSE;
  518.    printmsg(3, "dial: Modem reports connected");
  519.    time( &remote_stats.lconnect );
  520.    remote_stats.calls ++ ;
  521.  
  522.    autobaud(speed);        /* Reset modem speed, if desired          */
  523.  
  524. /*--------------------------------------------------------------------*/
  525. /*                      Report success to caller                      */
  526. /*--------------------------------------------------------------------*/
  527.  
  528.    return TRUE;            /* Dial succeeded    */
  529.  
  530. } /* dial */
  531.  
  532. /*--------------------------------------------------------------------*/
  533. /*    a u t o b a u d                                                 */
  534. /*                                                                    */
  535. /*    autobaud a modem which has just connected                       */
  536. /*--------------------------------------------------------------------*/
  537.  
  538. static void autobaud( const size_t speed )
  539. {
  540.    char buf[10];
  541.  
  542.    ssleep(1);                 /*  Allow modem port to stablize       */
  543.  
  544. /*--------------------------------------------------------------------*/
  545. /*                  Autobaud the modem if requested                   */
  546. /*--------------------------------------------------------------------*/
  547.  
  548.    if (!bmodemflag[MODEM_FIXEDSPEED])
  549.    {
  550.       size_t len = 0;
  551.  
  552.       memset( buf, '\0', sizeof( buf ));  /* Zero buffer                */
  553.       while ((len < sizeof buf) && sread( &buf[len],1,0))
  554.          len = strlen( buf );             /* Get speed into buffer      */
  555.  
  556.       if (len > 5)
  557.       {
  558.          char  *token;           /* Pointer to buffer value */
  559.          token = strtok(buf,WHITESPACE);
  560.          if (strlen(token))
  561.          {
  562.             size_t new_speed = (unsigned) atoi(token);
  563.             if ((new_speed != speed) && (new_speed > 300))
  564.             {
  565.                printmsg(2, "autobaud: speed select %s", token);
  566.                SIOSpeed(atoi(token));
  567.             } /* if */
  568.          } /* if */
  569.       } /* if */
  570.       else
  571.          printmsg(3, "autobaud: unable to speed select, using %d", speed);
  572.    } /* if */
  573.  
  574. } /* autobaud */
  575.  
  576. /*--------------------------------------------------------------------*/
  577. /*    s h u t d o w n                                                 */
  578. /*                                                                    */
  579. /*    Terminate modem processing via hangup                           */
  580. /*--------------------------------------------------------------------*/
  581.  
  582. void shutdown( void )
  583. {
  584.    static boolean recurse = FALSE;
  585.  
  586.    if ( !recurse )
  587.    {
  588.       recurse = TRUE;
  589.       hangup();
  590.       sendlist( dropline, modemTimeout, modemTimeout);
  591.       recurse = FALSE;
  592.    }
  593.    closeline();
  594. }
  595.  
  596. /*--------------------------------------------------------------------*/
  597. /*    s e n d l i s t                                                 */
  598. /*                                                                    */
  599. /*    Send a NULL terminated list of send/expect strings              */
  600. /*--------------------------------------------------------------------*/
  601.  
  602. static boolean sendlist( char **list, int timeout, int lasttimeout)
  603. {
  604.    boolean expect = TRUE;
  605.  
  606.    if (list == NULL)          /* Was the field supplied?             */
  607.       return TRUE;            /* No --> Must be optional, return     */
  608.  
  609. /*--------------------------------------------------------------------*/
  610. /*     Run through the list, alternating expect and send strings      */
  611. /*--------------------------------------------------------------------*/
  612.  
  613.    while( *list != NULL)
  614.    {
  615.       if (expect)
  616.       {
  617.          char *exp = strdup( *list );
  618.          boolean success;
  619.          checkref( exp );
  620.          success = sendalt( exp,
  621.                             (*(++list) == NULL) ? lasttimeout : timeout);
  622.          free( exp );
  623.          if (!success)
  624.             return FALSE;
  625.       }
  626.       else
  627.          sendstr( *list++ );
  628.       expect = ! expect;
  629.    } /* while */
  630.  
  631. /*--------------------------------------------------------------------*/
  632. /*    If we made it this far, success is at hand; return to caller    */
  633. /*--------------------------------------------------------------------*/
  634.  
  635.    return TRUE;
  636. } /* sendlist */
  637.  
  638. /*--------------------------------------------------------------------*/
  639. /*    s e n d a l t                                                   */
  640. /*                                                                    */
  641. /*    Expect a string, with alternates                                */
  642. /*--------------------------------------------------------------------*/
  643.  
  644. static boolean sendalt( char *exp, int timeout)
  645. {
  646.    boolean ok = FALSE;
  647.  
  648.    while (ok != TRUE) {
  649.       char *alternate = strchr(exp, '-');
  650.  
  651.       if (alternate != nil(char))
  652.          *alternate++ = '\0';
  653.  
  654.       ok = expectstr(exp, timeout);
  655.  
  656.       if (ok) {
  657.          printmsg(2, "got that");
  658.          break;
  659.       }
  660.  
  661.       if (alternate == nil(char)) {
  662.          return FALSE;
  663.       }
  664.  
  665.       exp = strchr(alternate, '-');
  666.       if (exp != nil(char))
  667.          *exp++ = '\0';
  668.  
  669.       printmsg(0, "sending alternate");
  670.       sendstr(alternate);
  671.    } /*while*/
  672.    return TRUE;
  673.  
  674. } /* sendalt */
  675.  
  676. /*--------------------------------------------------------------------*/
  677. /*    s l o w w r i t e                                               */
  678. /*                                                                    */
  679. /*    Write characters to the serial port at a configurable           */
  680. /*    snail's pace.                                                   */
  681. /*--------------------------------------------------------------------*/
  682.  
  683. void slowwrite( char *s, int len)
  684. {
  685.    swrite( s , len );
  686.    if (chardelay > 0)
  687.       ddelay(chardelay);
  688. } /* slowwrite */
  689.  
  690. /*--------------------------------------------------------------------*/
  691. /*    G e t G W i n d o w                                             */
  692. /*                                                                    */
  693. /*    Report the size of the allowed window for the "g" protocol      */
  694. /*--------------------------------------------------------------------*/
  695.  
  696. INTEGER  GetGWindow( INTEGER maxvalue )
  697. {
  698.    if ( (gWindow < 1 ) || (gWindow > maxvalue))
  699.       return maxvalue;
  700.    else
  701.       return gWindow;
  702. } /* GetGWindow */
  703.  
  704. /*--------------------------------------------------------------------*/
  705. /*    G e t G P a c k e t                                             */
  706. /*                                                                    */
  707. /*    Return the allowed packet size for the "g" procotol             */
  708. /*--------------------------------------------------------------------*/
  709.  
  710. INTEGER  GetGPacket( INTEGER maxvalue )
  711. {
  712.    if ( (gPacket < 1 ) || (gPacket > maxvalue))
  713.       return maxvalue;
  714.    else
  715.       return gPacket;
  716. } /* GetGPacket */
  717.  
  718.